<?php

interface Log{
    public function write();
}

class DatabaseLog implements Log{
    public function write()
    {
        echo 'database log write……';
    }
}

class FileLog implements Log{
    public function write()
    {
        echo 'file log write……';
    }
}

class User{
    protected $log;
    public function __construct(Log $log)
    {
        $this->log = $log;
    }

    public function login(){
        echo 'login success……';
        $this->log->write();
    }

}

class Ioc{
    protected $bindings = [];

    public function bind($abstract,$concrete){
        $this->bindings[$abstract]['concrete'] = function($ioc) use($concrete){
            return $ioc->build($concrete);
        };
    }

    public function make($abstract){
        return $this->bindings[$abstract]['concrete']($this);
    }

    public function build($concrete){
        $reflector = new ReflectionClass($concrete);
        $constructor = $reflector->getConstructor();
        if(is_null($constructor)){
            return $reflector->newInstance();
        }else{
            $dependencies = $constructor->getParameters();
            $instances = $this->getDependencies($dependencies);
            return $reflector->newInstanceArgs($instances);
        }
    }

    protected function getDependencies($parameters){
        $dependencies = [];
        foreach ($parameters as $parameter){
            $dependencies[] = $this->make($parameter->getClass()->name);
        }
        return $dependencies;
    }
}

class UserFacade{
    protected static $ioc;

    public static function setIoc($ioc){
        static::$ioc = $ioc;
    }

    public static function getFacadeAccessor(){
        return 'user';
    }

    public static function __callStatic($method, $arguments)
    {
        $instance = static::$ioc->make(static::getFacadeAccessor());
        return $instance->{$method}($arguments);
    }


}

$ioc = new Ioc();
$ioc->bind('Log','FileLog');
$ioc->bind('user','User');

UserFacade::setIoc($ioc);
UserFacade::login();